Trie树(小)总结Bycellur925 您所在的位置:网站首页 前缀树 python Trie树(小)总结Bycellur925

Trie树(小)总结Bycellur925

#Trie树(小)总结Bycellur925| 来源: 网络整理| 查看: 265

关于\(Trie\)树的详细介绍,还请移步这篇深度好文

基本操作

插入

void insert(){int p=0;int len=strlen(tmp+1);for(int i=1;i}

注意,其中\(tot=0\),我习惯\(p\)初始值也为\(0\)。\(tot\)与\(p\)初值应保持一致。

检索操作非常灵活,各题不同,但是都很简单,那么就自己想吧=w=(不负责地逃离)。

几道例题 简单题1:Luogu P3879 [TJOI2010]阅读理解

在每个文章记录一下出现次数即可。

#include#include#includeusing namespace std;int n,m,l,p,tot=1;int trie[500090][26];bool b[500000][1100];char word[25];void insert(char *str,int opt){int len=strlen(str);p=1;for(int k=0;k}void ask(char *str){int len=strlen(word);p=1;bool flag=1;for(int k=0;k} int main(){scanf("%d",&n);for(int i=1;i}

简单题2:UVA11362 Phone List

给定\(n\)个长度不超过\(10\)的数字串,判断是否有两个字符串\(A\)和\(B\),满足\(A\)是\(B\)的前缀。

满足题目中的条件对于每个串有两种情况:当这个串没读完的时候,有字符串以当前指针为结尾,说明之前串是当前串的前缀;这个串读完后,在计数数组中已经有记录,说明当前串是之前串的前缀。第一种情况开始被我忽略了。

分析完这点后,注意多组数据清空,空间开合适就好了。但是这题特别坑,存在的情况输出\(NO\),不存在输出\(YES\)。被坑了233.

#include#include#includeusing namespace std;int T,n,tot,lim;int trie[200900][20],endd[200090],cnt[200090];bool flag;char tmp[20];void in_trie(){int p=0,len=strlen(tmp+1);for(int i=1;i1) flag=1;}int main(){scanf("%d",&T);while(T--){flag=0;scanf("%d",&n);for(int i=1;i}

话说做这道题的时候开始用的数组叫\(end\)然后\(Compile\) \(error\)了...虚的一批。

简单题3:Luogu P2580 于是他错误的点名开始了

非常符合字典树的性质,直接上就行了。

#includeusing namespace std;int n,m,tot,p;int flag,end[1000090];int trie[1000090][27];char a[100];void insert(char *str){int len=strlen(str);p=1;for(int k=0;k}bool search(char *str){int len=strlen(str),p=1;for(int k=0;k}int main(){scanf("%d",&n);for(int i=1;i}

巧妙运用:\(01trie\)树

Luogu P4551 最长异或路径

给定一棵\(n\)个点的带权树,结点下标从\(1\)开始到\(N\)。在树中找两个结点,求最长的异或路径。

先考虑一个简化问题:给你一个数列,在其中任选两个数异或,求能获得的异或最大值。

考虑把\(32\)位的二进制\(01\)串强行塞到\(trie\)树上,这个树上的所有元素只可能为\(0\)或\(1\)。那么我们可以对于每个元素,在字典树上进行检索,每次尝试访问与这个元素的这个位的相反的指针,若指针指向空,那么只能访问和这位相同的指针。因为异或运算时“相同得1不同得0”的,所以这样能保证最优。

回到我们原来的问题之前,我们看另一道题:Luogu P2420 让我们异或吧。求两点间路径的所有边权的异或值。设\(d[i]\)为根节点到当前节点路径上的异或值。那么对于\((x,y)\)答案就是\(d[x]\) \(xor\) \(d[y]\)。为什么不用考虑他们的\(lca\)以上的部分呢,以为他们相同,一异或就会变成0了==。

代码还是稍微给一下?(虽然和今天的内容关系不大)

#includeusing namespace std;int n,m,tot;int head[200009];int xxor[200009],visit[200009];struct node{int to,val,next;}edge[200009];queueq;void add(int x,int y,int z){edge[++tot].to=y;edge[tot].val=z;edge[tot].next=head[x];head[x]=tot;}void bfs(){//queueq;q.push(1);visit[1]=1;while(!q.empty()){int x=q.front();q.pop();for(int i=head[x];i;i=edge[i].next){int y=edge[i].to;if(visit[y]) continue;visit[y]=1;xxor[y]=xxor[x]^edge[i].val;q.push(y);}}}int main(){scanf("%d",&n);for(int i=1;i}

回到我们最开始的问题==!有了前面两题的基础,那么我们在这个问题中要求的答案就等效于简化问题,只是数列变成了\(d[]\)。

#include#includeusing namespace std;int n,tot,ans;int d[100090],head[100090],trie[100090*32][5];struct node{int to,next,val;}edge[200090];void add(int x,int y,int z){edge[++tot].to=y;edge[tot].next=head[x];head[x]=tot;edge[tot].val=z;}void dfs(int u,int fa){for(int i=head[u];i;i=edge[i].next){int v=edge[i].to;if(v==fa) continue;d[v]=d[u]^edge[i].val;dfs(v,u);}}void insert(int x){int p=0;for(int i=(1>=1){bool qwq=x&i;//注意用bool if(!trie[p][qwq]) trie[p][qwq]=++tot;p=trie[p][qwq];}}int ask(int x){int p=0,orz=0;for(int i=(1>=1){bool qwq=x&i;if(trie[p][qwq^1]) orz+=i,p=trie[p][qwq^1];else p=trie[p][qwq];}return orz;}int main(){scanf("%d",&n);for(int i=1;i}

一定要注意\(qwq\)是\(bool\)类型的!这样保证只有0或1。如果是\(int\)的话,就不保证了!!(\(Warning\))

最后的最后

讨论下开空间的问题吧!

本蒟蒻几乎是做一道\(trie\)就\(RE\)一次...(逃)

比较玄学...尽量开大一点好(逃)



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有